home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 9 / AMUG BBS in a Box Volume IX (August 1993) (MacWizards).iso / Files / Prog / B-C / C++Source Code Fmtr.cpt / Src / FormatLog.cp / FormatLog.cp
Encoding:
Text File  |  1992-04-28  |  9.6 KB  |  452 lines  |  [TEXT/MPS ]

  1. #ifndef __CDENT__
  2. #include "cdent.h"
  3. #endif
  4.  
  5. #ifndef __FORMATLOG__
  6. #include "FormatLog.h"
  7. #endif
  8.  
  9. #ifndef __FORMATTING__
  10. #include "Formatting.h"
  11. #endif
  12.  
  13. #ifndef __SYNTACTIC__
  14. #include "Syntactic.h"
  15. #endif
  16.  
  17. #ifndef __OSUTILS__
  18. #include <osutils.h>
  19. #endif
  20.  
  21.  
  22.  
  23. /*µ class CheckpointItem
  24. **    A CheckpointItem is an element of the FormatLog queue.  It acts as a wrapper
  25. ** for the Formatting action itself.  The class is abstract because the action
  26. ** method, "Perform", must be overridden.  Also, operator new is overridden to
  27. ** use the queue for allocation.
  28. **    A caveat: the overridden Size() and Perform() methods must not expect "this"
  29. ** to remain unchanged as the object is being invoked in a handle.  You've been
  30. ** warned.
  31. */
  32. #pragma segment FormatLog
  33. class CheckpointItem : public SingleObject {
  34. public:
  35.     CheckpointItem();
  36.  
  37.     virtual void Perform(Formatting *aFormat) = 0;
  38.     // Abstract operation.  Perform() performs the action associated with
  39.     // each item using the information in aFormat to perform the
  40.     // requested operation.
  41.  
  42.     virtual size_t Size() const = 0;
  43.     // Return the size of the item in the queue.  Used by FormatLog::Redo
  44.     // to advance Next() and fNextRedo.
  45.  
  46.     void *operator new(size_t);
  47.     void *operator new(size_t aSize, DataArea *anArea);
  48.     inline void operator delete(void *);
  49.     /*
  50.     ** Override new.  The default method is overridden so that an error
  51.     ** occurs should anyone use it.  The DataArea* method is the new that
  52.     ** allocates out of a data area and the one which should be used
  53.     */
  54.  
  55.  
  56. private:
  57.     // No variables in root abstract class
  58. };
  59.  
  60.  
  61. // µ   CheckpointItem::CheckpointItem
  62. #pragma segment FormatLog
  63. inline CheckpointItem::CheckpointItem()
  64. {
  65. }
  66.  
  67.  
  68. // µ   CheckpointItem::operator delete
  69. #pragma segment FormatLog
  70. inline void CheckpointItem::operator delete(void *)
  71. {
  72. }
  73.  
  74.  
  75.  
  76. /*µ class CheckpointMethod
  77. **    This class wraps pure method calls.
  78. */
  79. #pragma segment FormatLog
  80. class CheckpointMethod : public CheckpointItem {
  81. public:
  82.     CheckpointMethod(void(Formatting::*aMethod)());
  83.     virtual void Perform(Formatting *aFormat);
  84.     virtual size_t Size() const;
  85.  
  86. private:
  87.     void(Formatting::*fMethod)();
  88. };
  89.  
  90.  
  91. // µ   CheckpointMethod::CheckpointMethod
  92. #pragma segment FormatLog
  93. inline CheckpointMethod::CheckpointMethod(void(Formatting::*aMethod)())
  94.     : fMethod(aMethod)
  95.     {
  96.     }
  97.  
  98.  
  99. // µ   CheckpointMethod::Perform
  100. #pragma segment FormatLog
  101. void CheckpointMethod::Perform(Formatting *aFormat)
  102. {
  103.     (aFormat->*fMethod)();
  104. }
  105.  
  106.  
  107. // µ   CheckpointMethod::Size
  108. #pragma segment FormatLog
  109. size_t CheckpointMethod::Size() const
  110. {
  111.     return (sizeof(*this));
  112. }
  113.  
  114.  
  115.  
  116. /*µ class CheckpointGlue
  117. **    This class wraps glue items and the method used to invoke them
  118. */
  119. #pragma segment FormatLog
  120. class CheckpointGlue : public CheckpointItem {
  121. public:
  122.     CheckpointGlue(void(Formatting::*aMethod)(FormatString), FormatString aGlue);
  123.  
  124.     virtual void Perform(Formatting *aFormat);
  125.     virtual size_t Size() const;
  126.  
  127. private:
  128.     void(Formatting::*fMethod)(FormatString);
  129.     FormatString fGlue;
  130. };
  131.  
  132.  
  133. // µ   CheckpointGlue::CheckpointGlue
  134. #pragma segment FormatLog
  135. inline CheckpointGlue::CheckpointGlue(void(Formatting::*aMethod)(FormatString), FormatString aGlue)
  136.     : fMethod(aMethod),
  137.       fGlue(aGlue)
  138.     {
  139.     }
  140.  
  141.  
  142. // µ   CheckpointGlue::Perform
  143. #pragma segment FormatLog
  144. void CheckpointGlue::Perform(Formatting *aFormat)
  145. {
  146.     (aFormat->*fMethod)(fGlue);
  147. }
  148.  
  149.  
  150. // µ   CheckpointGlue::Size
  151. #pragma FormatLog
  152. size_t CheckpointGlue::Size() const
  153. {
  154.     return (sizeof(*this));
  155. }
  156.  
  157.  
  158.  
  159. /*µ class CheckpointSyntactic
  160. **    This class wraps tokens and the method used to invoke them
  161. */
  162. #pragma segment FormatLog
  163. class CheckpointSyntactic : public CheckpointItem {
  164. public:
  165.     CheckpointSyntactic(void(Formatting::*aMethod)(Syntactic *), Syntactic *aToken);
  166.  
  167.     virtual void Perform(Formatting *aFormat);
  168.     virtual size_t Size() const;
  169. private:
  170.     void(Formatting::*fMethod)(Syntactic *);
  171.     Syntactic *fToken;
  172. };
  173.  
  174.  
  175. // µ   CheckpointSyntactic::CheckpointSyntactic
  176. #pragma segment FormatLog
  177. inline CheckpointSyntactic::CheckpointSyntactic(void(Formatting::*aMethod)(Syntactic *), Syntactic *aToken)
  178.     : fMethod(aMethod),
  179.       fToken(aToken)
  180.     {
  181.     fMethod = aMethod;
  182.     fToken = aToken;
  183.     }
  184.  
  185.  
  186. // µ   CheckpointSyntactic::Perform
  187. #pragma segment FormatLog
  188. void CheckpointSyntactic::Perform(Formatting *aFormat)
  189. {
  190.     (aFormat->*fMethod)(fToken);
  191. }
  192.  
  193.  
  194. // µ   CheckpointSyntactic::Size
  195. #pragma segment FormatLog
  196. size_t CheckpointSyntactic::Size() const
  197. {
  198.     return (sizeof(*this));
  199. }
  200.  
  201.  
  202.  
  203. /*µ class CheckpointBoolean
  204. **    This class wraps tokens and the method used to invoke them
  205. */
  206. #pragma segment FormatLog
  207. class CheckpointBoolean : public CheckpointItem {
  208. public:
  209.     CheckpointBoolean(void(Formatting::*aMethod)(Boolean), Boolean isGroup);
  210.  
  211.     virtual void Perform(Formatting *aFormat);
  212.     virtual size_t Size() const;
  213.  
  214. private:
  215.     void(Formatting::*fMethod)(Boolean);
  216.     Boolean fIsGroup;
  217. };
  218.  
  219.  
  220. // µ   CheckpointBoolean::CheckpointBoolean
  221. #pragma segment FormatLog
  222. inline CheckpointBoolean::CheckpointBoolean(void(Formatting::*aMethod)(Boolean), Boolean isGroup)
  223. {
  224.     // Initialize the variables
  225.     fMethod = aMethod;
  226.     fIsGroup = isGroup;
  227. }
  228.  
  229.  
  230. // µ   CheckpointBoolean::Perform
  231. #pragma segment FormatLog
  232. void CheckpointBoolean::Perform(Formatting *aFormat)
  233. {
  234.     (aFormat->*fMethod)(fIsGroup);
  235. }
  236.  
  237.  
  238. // µ   CheckpointBoolean::Size
  239. #pragma segment FormatLog
  240. size_t CheckpointBoolean::Size() const
  241. {
  242.     return (sizeof(*this));
  243. }
  244.  
  245.  
  246.  
  247.  
  248.  
  249.  
  250. /*
  251. ** Method implementation
  252. */
  253.  
  254.  
  255. //µ   FormatLog::~FormatLog
  256. #pragma segment FormatLog
  257. FormatLog::~FormatLog()
  258. {
  259.     if (fContext)
  260.         DisposHandle(fContext);
  261. }
  262.  
  263.  
  264. //µ   FormatLog::IFormatLog
  265. #pragma segment FormatLog
  266. short FormatLog::IFormatLog()
  267. {
  268.     short anErr;
  269.  
  270.     // Allow Record() to work
  271.     fState = kRecording;
  272.     fNextRedo = 0;
  273.     fCheckpoint = 0;
  274.  
  275.     anErr = fLog.IDataArea(64, 64);                // Just a guess.
  276.     if (anErr != noErr)
  277.         return (anErr);
  278.  
  279.     anErr = fSavedContexts.IDataArea(64, 64);
  280.     if (anErr != noErr)
  281.         return (anErr);
  282.  
  283.     fContext = NewHandle(sizeof(FContext));
  284.     return (fContext ? noErr : MemError());
  285. }
  286.  
  287.  
  288. // µ   FormatLog::IFormatLog
  289. #pragma segment FormatLog
  290. short FormatLog::IFormatLog(const FormatLog *aFormatLog)
  291. {
  292.     short anErr;
  293.  
  294.     fNextRedo = aFormatLog->fNextRedo;
  295.     fCheckpoint = aFormatLog->fCheckpoint;
  296.     fContext = aFormatLog->fContext;
  297.  
  298.     anErr = fLog.IDataArea(&aFormatLog->fLog);
  299.     if (anErr != noErr)
  300.         return (anErr);
  301.  
  302.     anErr = fSavedContexts.IDataArea(&aFormatLog->fSavedContexts);
  303.     if (anErr != noErr)
  304.         return (anErr);
  305.  
  306.     if (fContext)
  307.         return (HandToHand(&fContext));
  308.  
  309.     return (noErr);
  310. }
  311.  
  312.  
  313. //µ   FormatLog::Record
  314. #pragma segment FormatLog
  315. void FormatLog::Record(void(Formatting::*aMethod)())
  316. {
  317.     if (fState == kRecording)
  318.         new(&fLog)CheckpointMethod(aMethod);
  319. }
  320.  
  321.  
  322. // µ   FormatLog::Record
  323. #pragma segment FormatLog
  324. void FormatLog::Record(void(Formatting::*aMethod)(FormatString), FormatString aGlue)
  325. {
  326.     if (fState == kRecording)
  327.         new(&fLog)CheckpointGlue(aMethod, aGlue);
  328. }
  329.  
  330.  
  331. // µ   FormatLog::Record
  332. #pragma segment FormatLog
  333. void FormatLog::Record(void(Formatting::*aMethod)(Syntactic *), Syntactic *aToken)
  334. {
  335.     if (fState == kRecording)
  336.         new(&fLog)CheckpointSyntactic(aMethod, aToken);
  337. }
  338.  
  339.  
  340. // µ   FormatLog::Record
  341. #pragma segment FormatLog
  342. void FormatLog::Record(void(Formatting::*aMethod)(Boolean), Boolean isGroup)
  343. {
  344.     if (fState == kRecording)
  345.         new(&fLog)CheckpointBoolean(aMethod, isGroup);
  346. }
  347.  
  348.  
  349. //µ   FormatLog::RecordDepth
  350. #pragma segment FormatLog
  351. void FormatLog::RecordDepth(int aDepth)
  352. {
  353.     if (fState == kRecording)
  354.         if (aDepth < fMinDepth)
  355.             fMinDepth = aDepth;
  356.         else if (aDepth > fMaxDepth)
  357.             fMaxDepth = aDepth;
  358. }
  359.  
  360.  
  361. //µ   FormatLog::Checkpoint
  362. #pragma segment FormatLog
  363. void FormatLog::Checkpoint(const FContext *aContext, const DataArea *savedContexts, int aDepth)
  364. {
  365.     // Allow Record() to work
  366.     EnableRecord();
  367.  
  368.     // The context might have changed
  369.     **(FContext * *)fContext = *aContext;
  370.  
  371.     // Record the depth
  372.     fMinDepth = fMaxDepth = aDepth;
  373.  
  374.     // If no commands have been added, then savedContexts has not changed
  375.     // since the last call.  Return immediately.
  376.     if (fCheckpoint == Next())
  377.         return;
  378.  
  379.     // Save the data from the savedContexts stack into our area.
  380.     fSavedContexts.Assign(savedContexts);
  381.  
  382.     // Reset fLog, set fCheckpoint to the where the next Record() will
  383.     // drop its data.
  384.     fLog.SetCursor(0);
  385.     fCheckpoint = Next();
  386. }
  387.  
  388.  
  389. //µ   FormatLog::Rollback
  390. #pragma segment FormatLog
  391. void FormatLog::Rollback(FContext *aContext, DataArea *savedContexts)
  392. {
  393.     // Disable Record()
  394.     fState = kRedoing;
  395.  
  396.     // Position to the saved checkpoint marker
  397.     fNextRedo = fCheckpoint;
  398.  
  399.     // Restore the data from fSavedContexts into savedContexts.
  400.     *aContext = **(FContext * *)fContext;
  401.     savedContexts->Assign(&fSavedContexts);
  402. }
  403.  
  404.  
  405. //µ   FormatLog::Redo
  406. #pragma segment FormatLog
  407. Boolean FormatLog::Redo(Formatting *aFormat)
  408. {
  409.     // Check that there is something to execute.
  410.     if (fNextRedo >= Next() || fState != kRedoing)
  411.         return (false);
  412.  
  413.     // Get the next item from the queue and advance past it
  414.     CheckpointItem * anItem = (CheckpointItem *)fLog.GetData(fNextRedo);
  415.     fNextRedo += anItem->Size();
  416.  
  417.     // Execute it.  Notice that fLog is not locked as "Perform" goes in and
  418.     // out without referring to "this" after the pointer to method and any
  419.     // arguments have been referenced.
  420.     anItem->Perform(aFormat);
  421.     return (true);
  422. }
  423.  
  424.  
  425. //µ   CheckpointItem::operator new
  426. #pragma segment FormatLog
  427. void *CheckpointItem::operator new(size_t aSize, DataArea *anArea)
  428. {
  429.     // Check that there is space available in the queue.  If not, die the
  430.     // horrible death.
  431.     if (anArea->Require(aSize) < aSize) {
  432.         diag(kFatal, "Out of memory - CheckpointItem::operator new\n");
  433.         return (0);
  434.     }
  435.  
  436.     // Return a pointer and advance the cursor
  437.     void *aPtr = anArea->GetData();
  438.     anArea->IncrCursor(aSize);
  439.     return (aPtr);
  440. }
  441.  
  442.  
  443. // µ   CheckpointItem::operator
  444. #pragma segment FormatLog
  445. void *CheckpointItem::operator new(size_t)
  446. {
  447.     diag(kFatal, "Internal error: Checkpoint::operator new(size_t) called\n");
  448.     return (0);
  449. }
  450.  
  451.  
  452.